home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Interactive 7
/
PC World Interactive 7.iso
/
program
/
ctutor.exe
/
TEXT
/
CHAP11.TXT
< prev
next >
Wrap
Text File
|
1994-05-15
|
31KB
|
638 lines
Chapter 11
STRUCTURES AND UNIONS
WHAT IS A STRUCTURE?
-----------------------------------------------------------------
A structure is a user defined data type. Using ===============
a structure you have the ability to define a STRUCT1.C
new type of data considerably more complex than ===============
the types we have been using. A structure is a
combination of several different previously defined data types,
including other structures we have defined. A simple definition
is, "a structure is a grouping of related data in a way
convenient to the programmer or user of the program." The best
way to understand a structure is to look at an example, so if you
will load and display STRUCT1.C, we will do just that.
The program begins with a structure definition. The keyword
struct is followed by three simple variables between the braces,
which are the components of the structure. After the closing
brace, you will find two variable names listed, boy, and girl.
According to the definition of a structure, boy is now a variable
composed of three elements, initial, age, and grade. Each of the
three fields are associated with boy, and each can store a
variable of its respective type. The variable named girl is also
a variable containing three fields with the same names as those
of boy but are actually different variables. We have therefore
defined 6 simple variables, but they are grouped into 2 variables
of a structure type.
A SINGLE COMPOUND VARIABLE
-----------------------------------------------------------------
Lets examine the variable named boy more closely. As stated
above, each of the three elements of boy are simple variables and
can be used anywhere in a C program where a variable of their
type can be used. For example, the age element is an integer
variable and can therefore be used anywhere in a C program where
it is legal to use an integer variable, in calculations, as a
counter, in I/O operations, etc. We now have the problem of
defining how to use the simple variable named age which is a part
of the compound variable named boy. To do so we use both names
with a decimal point between them with the major name first.
Thus boy.age is the complete variable name for the age field of
boy. This construct can be used anywhere in a C program that it
is desired to refer to this field. In fact, it is illegal to use
the name boy or age alone because they are only partial
definitions of the complete field. Alone, the names refer to
nothing. (Actually the name boy alone does have meaning when
used with a modern C compiler. We will discuss this later.)
Page 11-1
Chapter 11 - Structures and Unions
ASSIGNING VALUES TO THE VARIABLES
-----------------------------------------------------------------
Using the above definition, we can assign a value to each of the
three fields of boy and each of the three fields of girl. Note
carefully that boy.initial is actually a char type variable,
because it was defined as one in the structure, so it must be
assigned a character of data. In line 12, boy.initial is
assigned the character R in agreement with the above rules. The
remaining two fields of boy are assigned values in accordance
with their respective types. Finally the three fields of girl
are assigned values but in a different order to illustrate that
the order of assignment is not critical. You will notice that
we used the value of the boy's age when we defined the girl's
age. This illustrates the use of one member of the structure.
Figure 11-1 is a graphical representation of the data following
execution of line 18.
HOW DO WE USE THE RESULTING DATA?
-----------------------------------------------------------------
Now that we have assigned values to the six simple variables, we
can do anything we desire with them. In order to keep this first
example simple, we will simply print out the values to see if
they really do exist as assigned. If you carefully inspect the
printf() statements, you will see that there is nothing special
about them. The compound name of each variable is specified
because that is the only valid name by which we can refer to
these variables.
Structures are a very useful method of grouping data together in
order to make a program easier to write and understand. This
first example is too simple to give you even a hint of the value
of using structures, but continue on through these lessons and
eventually you will see the value of using structures. Compile
and run STRUCT1.C and observe the output.
AN ARRAY OF STRUCTURES
-----------------------------------------------------------------
Load and display the next program named =================
STRUCT2.C. This program contains the same STRUCT2.C
structure definition as before but this time =================
we define an array of 12 variables named
kids. It should be clear that this program contains 12 times
3 = 36 simple variables, each of which can store one item of data
provided that it is of the correct type. We also define a simple
variable named index for use in the for loops.
In order to assign each of the fields a value, we use a for loop
and each pass through the loop results in assigning a value to
each of the fields of one structure variable. One pass through
the loop assigns all of the values for one of the kids. This
would not be a very useful way to assign data in a real
Page 11-2
Chapter 11 - Structures and Unions
situation, but a loop could read the data in from a file and
store it in the correct fields in a real application. You might
consider this the crude beginning of a data base, which it is.
In the next few instructions of this program we assign new values
to some of the fields to illustrate the method used to accomplish
this. It should be self explanatory, so no additional comments
will be given. Figure 11-2 is a graphical representation of the
data for this program following execution of line 22.
A RECENT UPGRADE TO THE C LANGUAGE
-----------------------------------------------------------------
All good C compilers will allow you to copy an entire structure
with one statement. This is a fairly recent addition to the C
language and is a part of the ANSI standard, so you should feel
free to use it with your C compiler if it is available. Line 24
is an example of using a structure assignment. In this
statement, all 3 fields of kids[4] are copied into their
respective fields of kids[10].
WE FINALLY DISPLAY ALL OF THE RESULTS
-----------------------------------------------------------------
The last few statements contain a for loop in which all of the
generated values are displayed in a formatted list. Compile and
run the program to see if it does what you expect it to do. You
will need to remove line 24 if your compiler does not support
structure assignments.
USING POINTERS AND STRUCTURES TOGETHER
-----------------------------------------------------------------
Examine the file named STRUCT3.C for an example ===============
of using pointers with structures. This STRUCT3.C
program is identical to the last program except ===============
that it uses pointers for some of the operations.
The first difference shows up in the definition of variables
following the structure definition. In this program we define a
pointer named point which is defined as a pointer that points to
the structure. It would be illegal to try to use this pointer to
point to any other variable type. There is a very definite
reason for this restriction in C as we have alluded to earlier
and will review in the next few paragraphs.
The next difference is in the for loop where we use the pointer
for accessing the data fields. Recall from chapter 8 of this
tutorial that we said that the name of an array is actually a
pointer to the first element of the array. Since kids is a
pointer variable that points to the first element of the array
which is a structure, we can define point in terms of kids. The
variable kids is a constant so it cannot be changed in value, but
Page 11-3
Chapter 11 - Structures and Unions
point is a pointer variable and can be assigned any value
consistent with its being required to point to the structure.
If we assign the value of kids to point then it should be clear
that point will also point to the first element of the array, a
structure containing three fields. Figure 11-3 is a graphical
representation of the data space following the first pass through
the loop starting in line 14.
POINTER ARITHMETIC
-----------------------------------------------------------------
Adding 1 to point will now cause it to point to the second field
of the array because of the way pointers are handled in C. The
system knows that the structure contains three variables and it
knows how many memory elements are required to store the complete
structure. Therefore if we tell it to add one to the pointer, it
will actually add the number of memory elements required to get
to the next element of the array. If, for example, we were to
add 4 to the pointer, it would advance the value of the pointer
4 times the size of the structure, resulting in it pointing 4
elements farther along the array. This is the reason a pointer
cannot be used to point to any data type other than the one for
which it was defined.
Now to return to the program displayed on your monitor. It
should be clear from the previous discussion that as we go
through the loop, the pointer will point to the beginning of one
of the array elements each time. We can therefore use the
pointer to reference the various elements of each of the
structures as we go through the loop. Referring to the elements
of a structure with a pointer occurs so often in C that a special
method of doing that was devised. Using point->initial is the
same as using (*point).initial which is really the way we did it
in the last two programs. Remember that *point is the stored
data to which the pointer points and the construct should be
clear. The "->" is made up of the minus sign and the greater
than sign. You will find experienced C programmers using this
pointer dereference profusely when you read their code in
magazines and other publications.
Since the pointer points to the structure, we must once again
define which of the elements we wish to refer to each time we
use one of the elements of the structure. There are, as we
have seen, several different methods of referring to the members
of the structure. When executing the for loop used for output at
the end of the program, we use three different methods of
referring to the structure elements. This would be considered
very poor programming practice, but is done this way here to
illustrate to you that they all lead to the same result. This
program will probably require some study on your part to fully
understand, but it will be worth your time and effort to grasp
these principles.
Page 11-4
Chapter 11 - Structures and Unions
Lines 30 and 31 are two additional examples of structure
assignment which do nothing useful, but are included here for
your benefit. Compile and run this program, and once again, if
your compiler does not support structure assignment, you will
need to remove lines 30 and 31.
NESTED AND NAMED STRUCTURES
-----------------------------------------------------------------
Examine the file named NESTED.C for an example ================
of a nested structure. The structures we have NESTED.C
seen so far have been very simple, although ================
useful. It is possible to define structures
containing dozens and even hundreds or thousands of elements but
it would be to the programmers advantage not to define all of the
elements at one pass but rather to use a hierarchical structure
definition. This will be illustrated with the program on your
monitor.
The first structure contains three elements but is followed by no
variable name. We therefore have not defined any variables, only
a structure, but since we have included a name at the beginning
of the structure, the structure is named person. The name person
can be used to refer to the structure but not to any variable of
this structure type. It is therefore a new type that we have
defined, and we can use the new type in the same way we use int,
char, or any other types that exist in C. The only restriction
is that this new name must always be associated with the keyword
struct.
The next structure definition contains three fields with the
middle field being the previously defined structure which we
named person. The variable which has the type of person is named
descrip. So the new structure contains two simple variables,
grade and a string named lunch, and the structure named descrip.
Since descrip contains three variables, the new structure
actually contains 5 variables. This structure is also given a
name alldat, which is another type definition. Finally we define
an array of 53 variables each with the structure defined by the
type alldat, and each with the name student. If that is clear,
you will see that we have defined a total of 53 times 5
variables, each of which is capable of storing a value.
Since we have a new type definition we can use it to define two
more variables. The variables teacher and sub are defined in
line 20 to be variables of the type alldat, so that each of these
two variables contain 5 fields in which we can store data.
Figure 11-4 is a graphical representation of the variable named
teacher after it is defined in line 20.
Page 11-5
Chapter 11 - Structures and Unions
NOW TO USE SOME OF THE FIELDS
-----------------------------------------------------------------
In lines 22 through 26 of the program, we will assign values to
each of the fields of teacher. The first field is the grade
field and is handled just like the other structures we have
studied because it is not part of the nested structure. Next we
wish to assign a value to her age which is part of the nested
structure. To address this field we start with the variable name
teacher to which we append the name of the group descrip, and
then we must define which field of the nested structure we are
interested in, so we append the variable name age. The teachers
status is handled in exactly the same manner as her age, but the
last two fields are assigned strings using the string copy
function strcpy() which must be used for string assignment.
Notice that the variable names in the strcpy() function are
still variable names even though they are made up of several
parts each.
The variable sub is assigned nonsense values in much the same
way, but in a different order since they do not have to occur in
any required order. Finally, a few of the student variables are
assigned values for illustrative purposes and the program ends.
None of the values are printed for illustration since several
were printed in the last examples.
Compile and run this program, but when you run it, you may get a
stack overflow error. C uses its own internal stack to store the
automatic variables, but some C compilers use only a 2048 byte
stack as a default. This program requires more than that for the
defined structures so it will be necessary for you to increase
the stack size. Consult your compiler documentation for details
concerning the method of increasing the stack size. There is no
standard way to do this. There is another way around this
problem, and that is to move the variable definitions outside of
the main program where they will be external variables and
therefore static. The result is that they will not be kept on
the internal stack and the stack will not overflow. It would be
good experience for you to try both methods of fixing this
problem.
MORE ABOUT STRUCTURES
-----------------------------------------------------------------
It is possible to continue nesting structures until you get
totally confused. If you define them properly, the computer will
not get confused because there is no stated limit as to how many
levels of nesting are allowed. There is probably a practical
limit of three beyond which you will probably get confused, but
the language has no limit. In addition to nesting, you can
include as many structures as you desire in any level of
structures, such as defining another structure prior to alldat
and using it in alldat in addition to using person. The
Page 11-6
Chapter 11 - Structures and Unions
structure named person could be included in alldat two or more
times if desired, as could pointers to it.
Structures can contain arrays of other structures which in turn
can contain arrays of simple types or other structures. It can
go on and on until you lose all reason to continue. I am only
trying to illustrate to you that structures are very valuable and
you will find them great aids to programming if you use them
wisely. Be conservative at first, and get bolder as you gain
experience. Keep in mind that a structure is designed to group
related data together.
More complex structures will not be illustrated here, but you
will find examples of additional structures in the example
programs included in the last chapter of this tutorial. For
example, see the include file named VC.H on the distribution
disk.
WHAT ARE UNIONS?
-----------------------------------------------------------------
Examine the file named UNION1.C for an example ================
of a union. Simply stated, a union allows you UNION1.C
a way to look at the same data with different ================
types, or to use the same data with different
names. In this example we have two elements to the union, the
first part being the integer named value, which is stored as a
two byte variable somewhere in the computers memory. The second
element is made up of two character variables named first and
second. These two variables are stored in the same storage
locations that value is stored in, because that is what a union
does. A union allows you to store different types of data in the
same physical storage locations. In this case, you could put an
integer number in value, then retrieve it in its two halves by
getting each half using the two names first and second. This
technique is often used to pack data bytes together when you are,
for example, combining bytes to be used in the registers of the
microprocessor.
Accessing the fields of the union are very similar to accessing
the fields of a structure and will be left to you to determine by
studying the example.
One additional note must be given here about the program. When
it is run using some C compilers, the data will be displayed with
two leading f's due to the hexadecimal output promoting the char
type variables to int and extending the sign bit to the left.
Converting the char type data fields to int type fields prior to
display should remove the leading f's from your display. This
will involve defining two new int type variables and assigning
the char type variables to them. This will be left as an
exercise for you. Note that the same problem will come up in a
few of the later files in this tutorial.
Page 11-7
Chapter 11 - Structures and Unions
Compile and run this program and observe that the data is read
out as an int and as two char variables. The char variables may
be reversed in order because of the way an int variable is stored
internally in your computer. If your system reverses these
variables, don't worry about it. It is not a problem but it can
be a very interesting area of study if you are so inclined.
ANOTHER UNION EXAMPLE
-----------------------------------------------------------------
Examine the file named UNION2.C for another =================
example of a union, one which is much more UNION2.C
common. Suppose you wished to build a large =================
database including information on many types
of vehicles. It would be silly to include the number of
propellers on a car, or the number of tires on a boat. In order
to keep all pertinent data, however, you would need those data
points for their proper types of vehicles. In order to build an
efficient data base, you would need several different types of
data for each vehicle, some of which would be common, and some of
which would be different. That is exactly what we are doing in
the example program on your monitor.
In this program, we will define a complete structure, then decide
which of the various types can go into it. We will start at the
top and work our way down. First, we define a few constants with
the #defines, and begin the program itself. We define a
structure named automobile containing several fields which you
should have no trouble recognizing, but we define no variables at
this time.
A NEW CONCEPT, THE TYPEDEF
-----------------------------------------------------------------
Next we define a new type of data with a typedef. This defines a
complete new type that can be used in the same way that int or
char can be used. Notice that the structure has no name, but at
the end where there would normally be a variable name there is
the name BOATDEF. We now have a new type, BOATDEF, that can be
used to define a structure anyplace we would like to. Notice
that this does not define any variables, only a new type.
Capitalizing the name is a personal preference only and is not a
C standard but is used by most experienced C programmers. It
makes the typedef look different from a variable name.
We finally come to the big structure that defines our data using
the building blocks already defined above. The structure is
composed of 5 parts, two simple variables named vehicle and
weight, followed by the union, and finally the last two simple
variables named value and owner. Of course the union is what we
need to look at carefully here, so focus on it for the moment.
You will notice that it is composed of four parts, the first part
being the variable car which is a structure that we defined
Page 11-8
Chapter 11 - Structures and Unions
previously. The second part is a variable named boat which is a
structure of the type BOATDEF previously defined. The third part
of the union is the variable airplane which is a structure
defined in place in the union. Finally we come to the last part
of the union, the variable named ship which is another structure
of the type BOATDEF.
I hope it is obvious to you that all four could have been defined
in any of the three ways shown, but the three different methods
were used to show you that any could be used. In practice, the
clearest definition would probably have occurred by using the
typedef for each of the parts.
WHAT DO WE HAVE NOW?
-----------------------------------------------------------------
We now have a structure that can be used to store any of four
different kinds of data structures. The size of every record
will be the size of that record containing the largest union. In
this case part 1 is the largest union because it is composed of
three integers, the others being composed of an integer and a
character each. The first member of this union would therefore
determine the size of all structures of this type. The resulting
structure can be used to store any of the four types of data, but
it is up to the programmer to keep track of what is stored in
each variable of this type. The variable named vehicle was
designed into this structure to keep track of the type of vehicle
stored here. The four defines at the top of the page were
designed to be used as indicators stored in the variable named
vehicle.
A few examples of how to use the resulting structure are given in
the next few lines of the program. Some of the variables are
defined and a few of them are printed out for illustrative
purposes.
The union is not used too frequently, and almost never by
beginning programmers. You will encounter it occasionally so it
is worth your effort to at least know what it is. You do not
need to know the details of it at this time, so don't spend too
much time studying it. When you do have a need for a variant
structure, a union, you can learn it at that time. For your own
benefit, however, do not slight the structure. You should use
the structure often.
WHAT IS A BITFIELD?
-----------------------------------------------------------------
Load and display the program named BITFIELD.C ================
for an example of how to define and use a BITFIELD.C
bitfield. In this program, we have a union ================
made up of a single int type variable in line
5 and the structure defined in lines 6 through 10. The structure
Page 11-9
Chapter 11 - Structures and Unions
is composed of three bitfields named x, y, and z. The variable
named x is only one bit wide, the variable y is two bits wide and
adjacent to the variable x, and the variable z is two bits wide
and adjacent to y. Moreover, because the union causes the bits
to be stored in the same memory location as the variable index,
the variable x is the least significant bit of the variable
index, y is the next two bits, and z is stored in the next two
bits of index.
Compile and run the program and you will see that as the variable
index is incremented by one each time through the loop, and you
will see the bitfields of the union counting due to their
respective locations within the int definition.
One thing must be pointed out, the bitfields must be defined as
parts of an unsigned int or your compiler will issue an error
message.
WHAT IS THE BITFIELD GOOD FOR?
-----------------------------------------------------------------
The bitfield is very useful if you have a lot of data to separate
into individual bits or groups of bits. Many systems use some
sort of a packed format to get lots of data stored in a few
bytes. Your imagination is your only limitation to the efficient
use of this feature of C.
MORE STYLE ISSUES
-----------------------------------------------------------------
Examine the file named STYLE3.H for our first ================
example of a header file that really looks STYLE3.H
like one. You will notice several constant ================
definitions, a few structure definitions, and
some prototypes. Nothing in this file generates anything that
uses memory, since there are no variables defined and no code is
defined here. Each of those use some memory, but all of the
constructs in this file do nothing but create definitions which
are then used by other portions of the program. This header
file, if it is general enough, can be used by many different
implementations.
Spend a few minutes and observe the style. Take notice
especially of the order of the various entities. The constants
are defined first, followed by the structures since they
generally use one or more of the constants. Finally, the
prototypes are defined since they often make use of one or more
of the structures in their parameter lists or their return
values.
Page 11-10
Chapter 11 - Structures and Unions
Examine the file named STYLE3.C which uses some ================
of the definitions in the header STYLE3.H STYLE3.C
header file. The observant student will notice ================
that not everything that is defined in the
header file is used in this implementation file, and it really
doesn't need to be. Since a header file is meant to be general
purpose, all things within the file will not be used every time
the file itself is used in a program.
In this case, the structure named alldat is used in lines 14 and
15, after being included here in line 10. The rest of the
program is written in exactly the same manner that it was
written when we defined the structure locally. This program can
be compiled and executed just like all of the other programs in
this tutorial.
PROGRAMMING EXERCISES
-----------------------------------------------------------------
1. Define a named structure containing a string for a name, an
integer for feet, and another for arms. Use the new type to
define an array of about 6 items. Fill the fields with data
and print them out as follows.
A human being has 2 legs and 2 arms.
A dog has 4 legs and 0 arms.
A television set has 4 legs and 0 arms.
A chair has 4 legs and 2 arms.
etc.
2. Rewrite exercise 1 using a pointer to print the data out.
Page 11-11